package references

import (
	"hundsun.com/hsl/hschain/contract/jvm/jvm.go/common"
	"hundsun.com/hsl/hschain/contract/jvm/jvm.go/instructions/base"
	"hundsun.com/hsl/hschain/contract/jvm/jvm.go/rtda"
	"hundsun.com/hsl/hschain/contract/jvm/jvm.go/rtda/heap"
	pbCommon "hundsun.com/hsl/hschain/protos/common"
	"hundsun.com/hsl/hschain/store/extend/contract"
)

// Set field in object
type PutField struct {
	base.Index16Instruction
	field *heap.Field
}

func (instr *PutField) Execute(frame *rtda.Frame) {
	if instr.field == nil {
		cp := frame.GetConstantPool()
		kFieldRef := cp.GetConstantFieldRef(instr.Index)
		instr.field = kFieldRef.GetField(false)
	}
	val := frame.PopL(instr.field.IsLongOrDouble)
	ref := frame.PopRef()
	if ref == nil {
		frame.Thread.ThrowNPE()
		return
	}

	instr.field.PutValue(ref, val)
	if !heap.IsJdkClass(instr.field.Class.Name) && !heap.IsBaseContractClass(instr.field.Class.Name) {
		//if instr.field.IsStorage() {
		isLocal := false
		for i, l := range frame.LocalVars.DebugGetSlots() {
			//localVars第一个参数为对象this指针
			if i == 0 {
				continue
			}
			if l.Ref != nil && l.Ref == ref {
				isLocal = true
				break
			}
		}
		//本地变量不需要存储
		if isLocal {
			return
		}

		thread := frame.Thread
		nsKvs := thread.StoreDataToStorage(instr.field, val)
		jlog := frame.Thread.Log
		jlog.Debugf("Put the storage type field %s:%s ", instr.field.Class.Name, instr.field.Name)
		for _, nsKv := range nsKvs {
			ctStat := &pbCommon.ContractStatus{
				Address:   thread.ContractName,
				Namespace: "ClassField",
				Key:       nsKv.Key,
				Value:     nsKv.Value,
			}
			kv, _ := contract.StatusKV(ctStat, common.ContractStatusTypeField)
			thread.ExecCtx.GetStateHandle().SetLocal(kv.Key, kv.Value)
			thread.GroupedTx.TxExecRst.Kvs = append(thread.GroupedTx.TxExecRst.Kvs, kv)
		}
		//}
	}
}
